package com.casit.base.jpa;


import org.springframework.util.StringUtils;

import javax.persistence.criteria.*;
import java.util.LinkedList;
import java.util.List;

public class DynamicSpecifications {
	/**
	 * 动态生成filter
	 * @param selectFilter 格式为 search=name:eq:billow36:[and | or];phone:like:130:[and | or];( state:gt:5:[and | or];flag:eq:5:[and | or])
	 * @param root
	 * @param query
	 * @param builder
	 * @param <T>
	 * @return
	 */
	public static <T> Predicate buildPredicate(
			String selectFilter
			, Root<T> root,
			CriteriaQuery<?> query, CriteriaBuilder builder) {
		Predicate predicate = null;
		String searchJoin="and";
		List<String> filterExp = split(selectFilter,";");

		if(filterExp.size()>0){
			for (String filter : filterExp) {
				//判断是否由括号包起来的表达式()，如果是，需要递归
				String exp =  filter.trim();
				if(exp.indexOf('(')==0){//如果是以括号开头的，必须有结束，否则直接过滤
					if(predicate== null){

						String subString = exp.substring(1,exp.lastIndexOf(")")-1);
						predicate=buildPredicate(subString,root,query,builder);
					}
					else if(searchJoin =="and"){
						if(")".equals(exp.substring(exp.length()-1))){
							predicate = builder.and(predicate,buildPredicate(exp.substring(1,exp.length()-1),root,query,builder));
						}
						else {
							int lastindex = exp.lastIndexOf("):");

							predicate = builder.and(predicate,buildPredicate(exp.substring(1,lastindex),root,query,builder));
						}
					}
					else {
						if(")".equals(exp.substring(exp.length()-1))){
							predicate = builder.or(predicate,buildPredicate(exp.substring(1,exp.length()-1),root,query,builder));
						}
						else {
							int lastindex = exp.lastIndexOf("):");
							predicate = builder.or(predicate,buildPredicate(exp.substring(1,lastindex),root,query,builder));
						}
					}
					String[] filterArray= exp.split("\\):");
					if(filterArray.length>=2){
						searchJoin=filterArray[filterArray.length-1].toLowerCase();
					}
					else {
						searchJoin="and";
					}

				}
				else{
					//查询是否有不需要转化的字符串
				     int beginIndex= exp.indexOf("$");
				     if(beginIndex!=-1){
				     	int lastIndex = exp.lastIndexOf("$");
				     	if(lastIndex<beginIndex){
				     		//如果不在一个范围内，需要
						}
					 }
					 List filterList = splitValue(exp,":") ;
				     if(!filterList.isEmpty()&&filter.length()>=2){
						 //以冒号分开
						 String[] filterArray=new String[filterList.size()] ;
						 filterList.toArray(filterArray);
						 Predicate pre = getPredicate(root,filterArray,builder);
						 if(pre!=null){
							 if(predicate== null){
								 predicate=pre;
							 }
							 else if("and".equals(searchJoin.toLowerCase())){
								 predicate = builder.and(predicate,pre);
							 }
							 else {
								 predicate = builder.or(predicate,pre);
							 }
							 if(filterArray.length>3){
								 searchJoin=filterArray[3].toLowerCase();
							 }
							 else {
								 searchJoin="and";
							 }
						 }
					 }


				}
			}
		}
		return predicate;
	}


	private static Predicate getPredicate(Root root,String[] filterArray, CriteriaBuilder builder){

		Predicate predicate=null;
		if((filterArray.length==2&&(filterArray[1].toUpperCase()=="ISNULL"||filterArray[1].toUpperCase()=="NOTNULL"))||filterArray.length>2){//表达式长度，必须大小2
			//属性名
			String[] propertyArray=filterArray[0].split("\\.");
		   Path<?> path =  getRootPath(root,propertyArray);
			String operation = filterArray[1];
			//Object obj = checkType(filterArray[2],path.getJavaType());
			switch (operation.toUpperCase()) {
				case "EQ"://等于
					predicate = builder.equal( path ,checkType(filterArray[2],path.getJavaType()));
					break;
				case "NEQ"://等于
					predicate = builder.notEqual( path,checkType(filterArray[2],path.getJavaType()));
					break;
				case "LIKE"://匹配
					predicate =builder.like(  getRootPath(root,propertyArray), "%" +checkType(filterArray[2],path.getJavaType())
							+ "%");
					break;
				case "NOTLIKE"://匹配
					predicate =builder.notLike(  getRootPath(root,propertyArray), "%" +checkType(filterArray[2],path.getJavaType())
							+ "%");
					break;
				case "GT"://大于
					predicate = builder.greaterThan(  getRootPath(root,propertyArray),(Comparable)checkType(filterArray[2],path.getJavaType()));
					break;
				case "LT"://小于
					predicate = builder.lessThan(  getRootPath(root,propertyArray),(Comparable)checkType(filterArray[2],path.getJavaType()));
					break;
				case "GTE"://大于等于
					predicate = builder.greaterThanOrEqualTo(getRootPath(root,propertyArray),(Comparable)checkType(filterArray[2],path.getJavaType()));
					break;
				case "LTE"://小于等于

					predicate = builder.lessThanOrEqualTo(getRootPath(root,propertyArray),(Comparable)checkType(filterArray[2],path.getJavaType()));
					break;
				case "BETWEEN"://属于
					String[] value= filterArray[2].split(",");
					if(value.length==1){
						predicate = builder.between(getRootPath(root,propertyArray),
								(Comparable)checkType(value[0],path.getJavaType()),(Comparable)checkType(value[0],path.getJavaType()));
					}
					else{
						predicate = builder.between(getRootPath(root,propertyArray),
								(Comparable)checkType(value[0],path.getJavaType()),(Comparable)checkType(value[1],path.getJavaType()));
					}
					break;
				case "ISNULL"://等于空
					predicate = builder.isNull(root.get(filterArray[0]));
					break;
				case "NOTNULL":
					predicate = builder.isNotNull(root.get(filterArray[0]));
					break;
				case "IN":
					predicate=root.get(filterArray[0]).in(changeValueToList(root.get(filterArray[0]).getJavaType(),filterArray[2],","));
					break;

			}

		}
		return  predicate;
	}
	private static<T> Path<?> getRootPath(Root<T> root,String[] property){
		if(property.length==1)
			return  root.get(property[0]);
		//还不明白具体的实现，现在硬编码
		Join<?,?> join= root.join(property[0]);
		for (int index = 1;index<property.length-1;index++){
			join = join.join(property[index]);
		}
		return join.get(property[property.length-1]);
	}


	public static <T> Object checkType(String value, Class<T> target) {

		try{//如果是包装类型，那么该方法不会报错
			return  target.getConstructor(String.class).newInstance(value);
		}
		catch (NoSuchMethodException mex){//如果是没有对应的方法，有可能是基础类型
			if(target.getName()== boolean.class.getName()){
				return  Boolean.parseBoolean(value);
			}else if(target.getName()== char.class.getName()){
				return  value.charAt(0);
			}
			else if(target.getName()== int.class.getName()){
				return  Integer.parseInt(value);
			}
			else if(target.getName()== byte.class.getName()){
				return  Byte.parseByte(value);
			}
			else if(target.getName()== short.class.getName()){
				return  Short.parseShort(value);
			}
			else if(target.getName()== long.class.getName()){
				return Long.parseLong(value);
			}
			else if(target.getName()== float.class.getName()){
				return Float.parseFloat(value);
			}
			else if(target.getName()== double.class.getName()){
				return Double.parseDouble(value);
			}
			return value;
		}
		catch (Exception ex){
			return value;
		}

	}
	private static List<Object> changeValueToList(Class typeName,String valueString,String split) {
		String[] valueArray = valueString.split(split);
		List<Object> valueList=new LinkedList<>();
		for(String str:valueArray){
			if(!StringUtils.isEmpty(str))
			valueList.add((Comparable)checkType(str,typeName));
		}
		return valueList;
	}

	/**
	 * 截取分割函数 createBy_:eq:casuser;(loginName:like:cas:or;loginName:eq:scadmin) 分成：createBy_:eq:casuser 和loginName:like:cas:or;loginName:eq:scadmin
	 * @param selectFilter
	 * @param splitCh
	 * @return
	 */
	private static List<String> split(String selectFilter,String splitCh){
		List<String> list = new LinkedList<>();
		selectFilter = selectFilter.trim();
		int lastIndex=0;
		if(selectFilter.indexOf("(")==0){//如果是以括号开头的，直接找）结束的字符串
			lastIndex= selectFilter.lastIndexOf(")");
			if(lastIndex == selectFilter.lastIndexOf("):or")){
				lastIndex=lastIndex+4;
				list.add(selectFilter.substring(0,lastIndex));
			}else if(lastIndex == selectFilter.lastIndexOf("):and")){
				lastIndex=lastIndex+5;
				list.add(selectFilter.substring(0,lastIndex));
			}else {
				list.add(selectFilter.substring(0,lastIndex+1));
			}
		}
		else {
			lastIndex = selectFilter.indexOf(splitCh);
			if(lastIndex==-1){
				list.add(selectFilter);
			}
			else{
				list.add(selectFilter.substring(0,lastIndex));
			}

		}
		if(lastIndex==-1||lastIndex==selectFilter.length()-1){
			return  list;

		}
		else {
			list.addAll(split(selectFilter.substring(lastIndex+1),splitCh));
		}
		return list;
	}

	private static List<String> splitValue(String selectFilter,String splitCh){
		List<String> list = new LinkedList<>();
		selectFilter = selectFilter.trim();
		int lastIndex=0;
		if(selectFilter.indexOf("$")==0){//如果是以括号开头的，直接找）结束的字符串
			lastIndex= selectFilter.lastIndexOf("$");
			list.add(selectFilter.substring(1,lastIndex));
			lastIndex++;
		}
		else {
			lastIndex = selectFilter.indexOf(splitCh);
			if(lastIndex==-1){
				list.add(selectFilter);
			}
			else{
				list.add(selectFilter.substring(0,lastIndex));
			}

		}
		if(lastIndex==-1||lastIndex>=selectFilter.length()-1){
			return  list;

		}
		else {
			list.addAll(splitValue(selectFilter.substring(lastIndex+1),splitCh));
		}
		return list;
	}
	public static  Predicate createByPredicate(
			String createBy,
			Root root,
			CriteriaQuery<?> query, CriteriaBuilder builder) {
		Path<String> userPath = root.get("xCreateBy");
		return  builder.equal(userPath,createBy);
	}
	public static  Predicate normalPredicate(
			char flag,
			Root root,
			CriteriaQuery<?> query, CriteriaBuilder builder) {
		Path<Integer> flag_ = root.get("xFlag");
		return  builder.equal(flag_,flag);
	}

}
